package felix.rule.web;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import felix.rule.data.entity.RuleChainEntity;
import felix.rule.data.msg.RuleChain;
import felix.rule.data.msg.RuleNode;
import felix.rule.data.plugin.ComponentLifecycleEvent;
import felix.rule.data.rule.RuleChainMetaData;
import felix.rule.service.ActorService;
import felix.rule.service.RuleChainService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@Slf4j
@RestController
@RequestMapping("/api")
public class RuleChainController {

    public static final String RULE_CHAIN_ID = "ruleChainId";

    @Autowired
    private RuleChainService ruleChainService;

    @Autowired
    private ActorService actorService;

    @RequestMapping(value = "/ruleChain/{ruleChainId}", method = RequestMethod.GET)
    @ResponseBody
    public RuleChain getRuleChainById(@PathVariable(RULE_CHAIN_ID) String ruleChainId) throws Exception {
        try {
            return ruleChainService.findRuleChainById(ruleChainId);
        } catch (Exception e) {
            log.error("Error [{}]", e.getMessage(), e);
            throw e;
        }
    }

    @RequestMapping(value = "/ruleChain/{ruleChainId}/metadata", method = RequestMethod.GET)
    @ResponseBody
    public RuleChainMetaData getRuleChainMetaData(@PathVariable(RULE_CHAIN_ID) String ruleChainId) throws Exception {
        try {
            return ruleChainService.loadRuleChainMetaData(ruleChainId);
        } catch (Exception e) {
            log.error("Error [{}]", e.getMessage(), e);
            throw e;
        }
    }


    @RequestMapping(value = "/ruleChain", method = RequestMethod.POST)
    @ResponseBody
    public RuleChain saveRuleChain(@RequestBody RuleChain ruleChain) throws Exception {
        try {
            boolean created = ruleChainService.saveRuleChain(ruleChain);
            actorService.onEntityStateChange(ruleChain.getRuleId(), RuleChain.class.getSimpleName(), ruleChain.getId(),
                    created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
            return ruleChain;
        } catch (Exception e) {
            log.error("Error [{}]", e.getMessage(), e);
            throw e;
        }
    }

    @RequestMapping(value = "/ruleChain/metadata", method = RequestMethod.POST)
    @ResponseBody
    public RuleChainMetaData saveRuleChainMetaData(@RequestBody RuleChainMetaData ruleChainMetaData) throws Exception {
        try {
            RuleChainMetaData savedRuleChainMetaData = ruleChainService.saveRuleChainMetaData(ruleChainMetaData);
            if (savedRuleChainMetaData != null) {
                actorService.onEntityStateChange(savedRuleChainMetaData.getRuleId(), RuleChain.class.getSimpleName(),
                        savedRuleChainMetaData.getRuleChainId(), ComponentLifecycleEvent.UPDATED);
                return savedRuleChainMetaData;
            } else {
                // TODO 空数据处理
                return null;
            }

        } catch (Exception e) {
            log.error("Error [{}]", e.getMessage(), e);
            throw e;
        }
    }

    @RequestMapping(value = "/ruleChains", method = RequestMethod.GET)
    @ResponseBody
    public IPage<RuleChain> getRuleChains(Page<RuleChainEntity> page,
                                          @RequestParam(required = false) String ruleId,
                                          @RequestParam(required = false) String name) throws Exception {
        try {
            return ruleChainService.findRuleChain(page, ruleId, name);
        } catch (Exception e) {
            log.error("Error [{}]", e.getMessage(), e);
            throw e;
        }
    }

    @RequestMapping(value = "/ruleChain/{ruleChainId}", method = RequestMethod.DELETE)
    @ResponseStatus(value = HttpStatus.OK)
    public void deleteRuleChain(@PathVariable(RULE_CHAIN_ID) String ruleChainId) throws Exception {
        try {
            RuleChain ruleChain = ruleChainService.findRuleChainById(ruleChainId);
            if (ruleChain != null) {
                List<RuleNode> referencingRuleNodes = ruleChainService.getReferencingRuleChainNodes(ruleChain.getRuleId(), ruleChainId);
                ruleChainService.deleteRuleChainById(ruleChainId);
                // 更新引用规则链
                referencingRuleNodes.forEach(ruleNode -> {
                    RuleChain ruleChainById = ruleChainService.findRuleChainById(ruleNode.getRuleChainId());
                    actorService.onEntityStateChange(ruleChainById.getRuleId(), RuleChain.class.getSimpleName(),
                            ruleNode.getRuleChainId(), ComponentLifecycleEvent.UPDATED);
                });
                actorService.onEntityStateChange(ruleChain.getRuleId(), RuleChain.class.getSimpleName(), ruleChainId, ComponentLifecycleEvent.DELETED);
            }
        } catch (Exception e) {
            log.error("Error [{}]", e.getMessage(), e);
            throw e;
        }
    }
}
